package com.zzedu.framework.security;

import com.alibaba.fastjson.JSON;
import com.zzedu.common.constant.CacheConstants;
import com.zzedu.common.enums.LoginType;
import com.zzedu.common.enums.PlatformLoginEnumns;
import com.zzedu.common.enums.UserTypeEnumns;
import com.zzedu.framework.web.domain.LoginForm;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.collections4.MapUtils;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.stereotype.Component;
import org.springframework.util.MimeTypeUtils;

import java.io.IOException;
import java.util.Map;

/**
 * https://blog.csdn.net/hjg719/article/details/128302584
 * <p>
 * <p>
 * 核心组件
 * MyLoginFilter(登陆过滤器)
 * <p>
 * 构造方法的参数都可以从容器获取，所以这里也直接注册到容器自动构造
 * 继承了UsernamePasswordAuthenticationFilter，后续我们要用它替换默认的UsernamePasswordAuthenticationFilter
 * 构造函数中，指定了：
 * 登陆成功和失败时的处理方法
 * 记住我功能的组件
 * 登陆使用的路径
 * attemptAuthentication方法中规定了登陆流程：
 * 如果Content-Type是Json，则从Body中获取请求参数，否则从Form表单中获取
 * 从Session的Attribute中获取之前保存的验证码，和用户提供的验证码进行比对
 * 把用户提供的rememberMe字段放到request的Attribute中，供后续MyRememberMeServices获取
 * 结尾部分来自父类，照抄过来的。
 */
@Component
public class MyLoginFilter extends UsernamePasswordAuthenticationFilter {
    public MyLoginFilter(AuthenticationManager authenticationManager,
                         MyAuthenticationHandler authenticationHandler) throws Exception {
        super(authenticationManager);
        setAuthenticationFailureHandler(authenticationHandler);
        setAuthenticationSuccessHandler(authenticationHandler);
        //登陆使用的路径
        setFilterProcessesUrl("/ajaxLogin");
    }

    private static boolean isContentTypeJson(HttpServletRequest request) {
        final String contentType = request.getContentType();
        return MyAuthenticationHandler.APPLICATION_JSON_CHARSET_UTF_8.equalsIgnoreCase(contentType) || MimeTypeUtils.APPLICATION_JSON_VALUE.equalsIgnoreCase(contentType);
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {

        if (!HttpMethod.POST.name().equalsIgnoreCase(request.getMethod())) {
            throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
        }
        String username = null;
        String password = null;
        String verifyCode = null;
        String userType = null;
        if (isContentTypeJson(request)) {
            try {
                Map map = JSON.parseObject(request.getInputStream(), Map.class);
                username = MapUtils.getString(map, getUsernameParameter());
                password = MapUtils.getString(map, getPasswordParameter());
                userType = MapUtils.getString(map, "userType");
                verifyCode = MapUtils.getString(map, "verifyCode");
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else {
            username = obtainUsername(request);
            password = obtainPassword(request);
            userType = request.getParameter("userType");
            verifyCode = request.getParameter("verifyCode");
        }
//        //校验验证码
        final String vc = (String) request.getSession().getAttribute(CacheConstants.CAPTCHA_CODE_KEY);
        if (vc == null) {
            throw new BadCredentialsException("验证码不存在,请先获取验证码");
        } else if (verifyCode == null || "".equals(verifyCode)) {
            throw new BadCredentialsException("请输入验证码");
        } else if (!vc.equalsIgnoreCase(verifyCode)) {
            throw new BadCredentialsException("验证码错误");
        }
        username = (username != null) ? username.trim() : "";
        password = (password != null) ? password : "";
        LoginForm loginForm = new LoginForm();
        loginForm.setLoginType(LoginType.PWD);
        loginForm.setPlatformLoginEnumns(PlatformLoginEnumns.PC);
        loginForm.setPassword(password);
        loginForm.setUsername(username);
        loginForm.setUserTypeEnumns(UserTypeEnumns.PLATFORM);
        UsernamePasswordAuthenticationToken authRequest = UsernamePasswordAuthenticationToken.unauthenticated(JSON.toJSONString(loginForm), password);
        setDetails(request, authRequest);
        return this.getAuthenticationManager().authenticate(authRequest);
    }
}

